package com.javacv.plus.core.metrics;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.DoubleAdder;

/**
 * 处理器性能监控和指标系统
 * 收集和统计处理器的性能数据
 */
@Slf4j
public class ProcessorMetrics {
    
    private final Map<String, StepMetrics> stepMetrics = new ConcurrentHashMap<>();
    private final AtomicLong totalProcessCount = new AtomicLong(0);
    private final AtomicLong totalSuccessCount = new AtomicLong(0);
    private final AtomicLong totalFailureCount = new AtomicLong(0);
    private final DoubleAdder totalProcessTime = new DoubleAdder();
    
    /**
     * 记录处理步骤开始
     */
    public ProcessingTimer startTiming(String stepName) {
        return new ProcessingTimer(stepName, this);
    }
    
    /**
     * 记录处理步骤完成
     */
    public void recordStepCompletion(String stepName, long duration, boolean success) {
        StepMetrics metrics = stepMetrics.computeIfAbsent(stepName, k -> new StepMetrics());
        metrics.recordExecution(duration, success);
        
        totalProcessCount.incrementAndGet();
        totalProcessTime.add(duration);
        
        if (success) {
            totalSuccessCount.incrementAndGet();
        } else {
            totalFailureCount.incrementAndGet();
        }
        
        log.debug("步骤完成: {}，耗时: {}ms，成功: {}", stepName, duration, success);
    }
    
    /**
     * 获取全局统计
     */
    public GlobalMetrics getGlobalMetrics() {
        long totalCount = totalProcessCount.get();
        long successCount = totalSuccessCount.get();
        long failureCount = totalFailureCount.get();
        double avgTime = totalCount == 0 ? 0.0 : totalProcessTime.sum() / totalCount;
        double successRate = totalCount == 0 ? 0.0 : (double) successCount / totalCount;
        
        return new GlobalMetrics(totalCount, successCount, failureCount, 
                                avgTime, successRate);
    }
    
    /**
     * 获取步骤统计
     */
    public Map<String, StepMetrics> getStepMetrics() {
        return new ConcurrentHashMap<>(stepMetrics);
    }
    
    /**
     * 获取指定步骤的统计
     */
    public StepMetrics getStepMetrics(String stepName) {
        return stepMetrics.get(stepName);
    }
    
    /**
     * 清除所有指标
     */
    public void clear() {
        stepMetrics.clear();
        totalProcessCount.set(0);
        totalSuccessCount.set(0);
        totalFailureCount.set(0);
        totalProcessTime.reset();
        log.info("性能指标已清空");
    }
    
    /**
     * 打印性能报告
     */
    public void printReport() {
        GlobalMetrics global = getGlobalMetrics();
        
        log.info("=== 处理器性能报告 ===");
        log.info("总处理次数: {}", global.getTotalCount());
        log.info("成功次数: {}", global.getSuccessCount());
        log.info("失败次数: {}", global.getFailureCount());
        log.info("平均耗时: {:.2f}ms", global.getAverageTime());
        log.info("成功率: {:.2f}%", global.getSuccessRate() * 100);
        log.info("");
        
        log.info("=== 步骤详细统计 ===");
        stepMetrics.forEach((stepName, metrics) -> {
            log.info("步骤: {}", stepName);
            log.info("  执行次数: {}", metrics.getExecutionCount());
            log.info("  成功次数: {}", metrics.getSuccessCount());
            log.info("  失败次数: {}", metrics.getFailureCount());
            log.info("  平均耗时: {:.2f}ms", metrics.getAverageTime());
            log.info("  最大耗时: {}ms", metrics.getMaxTime());
            log.info("  最小耗时: {}ms", metrics.getMinTime());
            log.info("  成功率: {:.2f}%", metrics.getSuccessRate() * 100);
            log.info("");
        });
    }
    
    /**
     * 步骤指标
     */
    public static class StepMetrics {
        private final AtomicLong executionCount = new AtomicLong(0);
        private final AtomicLong successCount = new AtomicLong(0);
        private final AtomicLong failureCount = new AtomicLong(0);
        private final DoubleAdder totalTime = new DoubleAdder();
        private volatile long maxTime = 0;
        private volatile long minTime = Long.MAX_VALUE;
        
        public void recordExecution(long duration, boolean success) {
            executionCount.incrementAndGet();
            totalTime.add(duration);
            
            // 更新最大最小时间
            if (duration > maxTime) {
                maxTime = duration;
            }
            if (duration < minTime) {
                minTime = duration;
            }
            
            if (success) {
                successCount.incrementAndGet();
            } else {
                failureCount.incrementAndGet();
            }
        }
        
        public long getExecutionCount() { return executionCount.get(); }
        public long getSuccessCount() { return successCount.get(); }
        public long getFailureCount() { return failureCount.get(); }
        public double getAverageTime() { 
            long count = executionCount.get();
            return count == 0 ? 0.0 : totalTime.sum() / count; 
        }
        public long getMaxTime() { return maxTime == 0 ? 0 : maxTime; }
        public long getMinTime() { return minTime == Long.MAX_VALUE ? 0 : minTime; }
        public double getSuccessRate() { 
            long count = executionCount.get();
            return count == 0 ? 0.0 : (double) successCount.get() / count; 
        }
    }
    
    /**
     * 全局指标
     */
    @Data
    public static class GlobalMetrics {
        private final long totalCount;
        private final long successCount;
        private final long failureCount;
        private final double averageTime;
        private final double successRate;
    }
    
    /**
     * 计时器
     */
    public static class ProcessingTimer implements AutoCloseable {
        private final String stepName;
        private final ProcessorMetrics metrics;
        private final long startTime;
        private boolean success = true;
        
        public ProcessingTimer(String stepName, ProcessorMetrics metrics) {
            this.stepName = stepName;
            this.metrics = metrics;
            this.startTime = System.currentTimeMillis();
        }
        
        public void markFailure() {
            this.success = false;
        }
        
        @Override
        public void close() {
            long duration = System.currentTimeMillis() - startTime;
            metrics.recordStepCompletion(stepName, duration, success);
        }
    }
} 